/*******************************************************************************
 * Copyright (C) 2019 China Micro Semiconductor Limited Company. All Rights Reserved.
 *
 * This software is owned and published by:
 * CMS LLC, No 2609-10, Taurus Plaza, TaoyuanRoad, NanshanDistrict, Shenzhen, China.
 *
 * BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
 * BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
 *
 * This software contains source code for use with CMS
 * components. This software is licensed by CMS to be adapted only
 * for use in systems utilizing CMS components. CMS shall not be
 * responsible for misuse or illegal use of this software for devices not
 * supported herein. CMS is providing this software "AS IS" and will
 * not be responsible for issues arising from incorrect user implementation
 * of the software.
 *
 * This software may be replicated in part or whole for the licensed use,
 * with the restriction that this Disclaimer and Copyright notice must be
 * included with each copy of this software, whether used in part or whole,
 * at all times.
 */

/****************************************************************************/
/** \file adcb.c
**
**	History:
**
*****************************************************************************/
/****************************************************************************/
/*	include files
*****************************************************************************/
#include "adc.h"
/****************************************************************************/
/*	Local pre-processor symbols/macros('#define')
*****************************************************************************/

/****************************************************************************/
/*	Global variable definitions(declared in header file with 'extern')
*****************************************************************************/

/****************************************************************************/
/*	Local type definitions('typedef')
*****************************************************************************/

/****************************************************************************/
/*	Local variable  definitions('static')
*****************************************************************************/

/****************************************************************************/
/*	Local function prototypes('static')
*****************************************************************************/

/****************************************************************************/
/*	Function implementation - global ('extern') and local('static')
*****************************************************************************/

/*****************************************************************************
 ** \brief	ADCB_ConfigRunMode
 **			设置ADC运行模式
 ** \param [in] RunMode: (1)ADCB_MODE_HIGH
 **						 (2)ADCB_MODE_LOW
 **				ConvertMode:(1)ADCB_CONVERT_SINGLE
 **							(2)ADCB_CONVERT_CONTINUOUS
 **				ClkDiv :(1)ADCB_CLK_DIV_1
 **						(2)ADCB_CLK_DIV_2
 **						(3)ADCB_CLK_DIV_4
 **						(4)ADCB_CLK_DIV_8
 **						(5)ADCB_CLK_DIV_16
 **						(6)ADCB_CLK_DIV_32
 **						(7)ADCB_CLK_DIV_64
 **						(8)ADCB_CLK_DIV_128
 **				Holdtime: 5.5~255.5 每增加1增加一个ADC clockcycles
 **                 0x05 = 5.5个ADC clockcycles
 **									.....
 **									0xff: 255.5个ADC clockcycles
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_ConfigRunMode(uint32_t RunMode, uint32_t ConvertMode, uint32_t ClkDiv, uint32_t Holdtime)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADMODE10_Msk | ADCB_CON_ADCMS_Msk | ADCB_CON_ADCDIV_Msk | ADCB_CON_ADCNSMP_Msk);
    ADCB->CON |= ConvertMode | ClkDiv | (Holdtime << ADCB_CON_ADCNSMP_Pos) | RunMode;
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_ConfigChannelSwitchMode
 **			设置ADCB通道切换模式
 ** \param [in] 	ChSwitch:(1)ADCB_SWITCH_HARDWARE
 **							 (2)ADCB_SWITCH_SOFTWARE
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_ConfigChannelSwitchMode(uint32_t ChSwitch)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCSWCHE_Msk);
    ADCB->CON |= ChSwitch;
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableCharge
 **			开启ADCB充电功能
 ** \param [in] ChargeTime:	ADCB_CG_2...... ADCB_CG_15
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableCharge(uint32_t ChargeTime)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCNDISTS_Msk);
    ADCB->CON |= ADCB_CON_ADCNDISEN_Msk | (ChargeTime << ADCB_CON_ADCNDISTS_Pos);
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_EnableDischarge
 **			开启ADCB放电功能
 ** \param [in] ChargeTime:	ADCB_CG_2...... ADCB_CG_15
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableDischarge(uint32_t ChargeTime)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCNDISEN_Msk | ADCB_CON_ADCNDISTS_Msk);
    ADCB->CON |= (ChargeTime << ADCB_CON_ADCNDISTS_Pos);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_DisableChargeAndDischarge
 **			关闭ADCB放电、充电功能
 ** \param [in] none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableChargeAndDischarge(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCNDISTS_Msk);
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_ConfigVREF
 **			设置ADCB的参考源
 ** \param [in]  VrefPos:  (1)ADCB_VREFP_VDD		选择VDD作为正端参考
 **						   (2)ADCB_VREFP_AVREFP		选择外部AVREFP作为正端参考
 **				 VrefNeg:  (1)ADCB_VREFN_VSS		选择部VSS作为负端参考
 **						   (2)ADCB_VREFN_AVREFN		选择外部AVREFN作为负端参考
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_ConfigVREF(uint32_t VrefPos, uint32_t VrefNeg)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCVS_Msk | ADCB_CON_ADCVG_Msk);
    ADCB->CON |= (VrefPos | VrefNeg);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_ConfigSampleTime
 **			配置采样时间
 ** \param [in]  sampletime: 5 ~ 255;
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_ConfigSampleTime(uint32_t sampletime)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCNSMP_Msk);
    ADCB->CON |= (sampletime << ADCB_CON_ADCNSMP_Pos);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableSampleWait
 **			使能ADCB保持采样状态
 ** \param [in]  none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableSampleWait(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON |= ADCB_CON2_ADCSMPWAIT_Msk;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableSampleWait
 **			关闭ADCB保持采样状态
 ** \param [in]  none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableSampleWait(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON2_ADCSMPWAIT_Msk);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_SelSoftwareSwitchChannel
 **			选择软件切换转换的通道
 ** \param [in] Channel: ADCB_CH_0 ~ ADCB_CH_30
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_SelSoftwareSwitchChannel(uint32_t Channel)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON2 &= ~(ADCB_CON2_ADCSWCHS_Msk);
    ADCB->CON2 |= Channel;
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_AN30Select
 **			AN30通道选择
 ** \param [in] AN30Sel : (1)ADCB_AN30_SEL_BG
 **						  (6)ADCB_AN30_SEL_VSS
 **						  (7)ADCB_AN30_SEL_AVDD
 **						  (8)ADCB_AN30_SEL_AVSS
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_AN30Select(uint32_t AN30Sel)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON2 &= ~(ADCB_CON2_ADCICHS_Msk);
    ADCB->CON2 |= (AN30Sel << ADCB_CON2_ADCICHS_Pos);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableScanChannel
 **			开启ADCB转换通道
 ** \param [in] ChannelMask: ADCB_CH_0_MSK ~ ADCB_CH_19_MSK
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableScanChannel(uint32_t ChannelMask)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->SCAN |= ChannelMask;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableScanChannel
 **			关闭ADCB转换通道
 ** \param [in] ChannelMask: ADCB_CH_0_MSK ~ ADCB_CH_19_MSK
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableScanChannel(uint32_t ChannelMask)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->SCAN &= ~(ChannelMask);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_GetResult
 **			获取ADCB转换结果
 ** \param [in] Channel: ADCB_CH_0 ~ ADCB_CH_30
 ** \return  12 bits Value
 ** \note
 *****************************************************************************/
uint32_t ADCB_GetResult(uint32_t Channel)
{
    return (ADCB->DATA[Channel]);
}

/*****************************************************************************
 ** \brief	ADCB_EnableHardwareTrigger
 **			开启硬件触发ADCB转换功能
 ** \param [in] TriggerSource:
 **							(1)ADCB_TG_INTNEL_ADCB
 **							(2)ADCB_TG_INTNEL_TMR0
 **							(3)ADCB_TG_INTNEL_TMR1
 **							(4)ADCB_TG_INTNEL_TMR2
 **							(5)ADCB_TG_INTNEL_TMR3
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableHardwareTrigger(uint32_t TriggerSource)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    switch (TriggerSource)
    {
    case ADCB_TG_INTNEL_ADCB:
    case ADCB_TG_INTNEL_TMR0:
    case ADCB_TG_INTNEL_TMR1:
    case ADCB_TG_INTNEL_TMR2:
    case ADCB_TG_INTNEL_TMR3:
        ADCB->HWTG &= ~(ADCB_HWTG_ADCINTTGSS_Msk);
        ADCB->HWTG |= TriggerSource;
        break;
    default:
        break;
    }
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableHardwareTrigger
 **			关闭硬件触发ADCB转换功能
 ** \param [in] TriggerSource:
 **							(1)ADCB_TG_INTNEL_ADCB
 **							(2)ADCB_TG_INTNEL_TMR0
 **							(3)ADCB_TG_INTNEL_TMR1
 **							(4)ADCB_TG_INTNEL_TMR2
 **							(5)ADCB_TG_INTNEL_TMR3
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableHardwareTrigger(uint32_t TriggerSource)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    switch (TriggerSource)
    {
    case ADCB_TG_INTNEL_ADCB:
    case ADCB_TG_INTNEL_TMR0:
    case ADCB_TG_INTNEL_TMR1:
    case ADCB_TG_INTNEL_TMR2:
    case ADCB_TG_INTNEL_TMR3:
        ADCB->HWTG &= ~(ADCB_HWTG_ADCINTTGEN_Msk);
        break;
    default:
        break;
    }
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_SetAnalogSwitchDelayTime
 **			设置ADCB 模拟开关打开到开始采样的时间
 ** \param [in] DelayTime: 0x00~ 0xff;
 ** \return  none
 ** \note  Time = (DelayTime+2)*ADCCLK
 *****************************************************************************/
void ADCB_SetAnalogSwitchDelayTime(uint32_t DelayTime)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->TEST = ((0xff & DelayTime) << ADCB_TEST_ADCSWT_Pos);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableCompare
 **			开启ADCB比较功能
 ** \param [in] Compare : ADCB_CMP0 、ADCB_CMP1
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableCompare(uint32_t Compare)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CMP[Compare] |= ADCB_CMP_ADCCMPEN_Msk;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableCompare
 **			关闭ADCB比较功能
 ** \param [in] Compare : ADCB_CMP0 、ADCB_CMP1
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableCompare(uint32_t Compare)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CMP[Compare] &= ~(ADCB_CMP_ADCCMPEN_Msk);
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_ConfigCompare
 **			配置ADCB比较功能
 ** \param [in] Compare : ADCB_CMP0 、ADCB_CMP1
 **				 CmpMode:(1)ADCB_CMP_LESS_THAN_RESULT
 **						(2)ADCB_CMP_NOT_LESS_THAN_RESULT
 **				 CmpCount: 0x00~0xf  预设比较次数
 **				 CmpChannel: ADCB_CH_0 ~ ADCB_CH_30
 **				 CmpData : 12 bit 比较值
 ** \return  none
 ** \note	当内部计数器等于ADCCMPxMCNT+1的值时产生ADC比较事件。
 *****************************************************************************/
void ADCB_ConfigCompare(uint32_t Compare, uint32_t CmpMode, uint32_t CmpCount,
                        uint32_t CmpChannel, uint32_t CmpData)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CMP[Compare] &= ~(ADCB_CMP_ADCCMPCOND_Msk | ADCB_CMP_ADCCMPMCNT_Msk |
                            ADCB_CMP_ADCCMPCHS_Msk | ADCB_CMP_ADCCMPDATA_Msk);
    ADCB->CMP[Compare] |= CmpMode | ((0xf & CmpCount) << ADCB_CMP_ADCCMPMCNT_Pos) | ((0x1f & CmpChannel) << ADCB_CMP_ADCCMPCHS_Pos) |
                          (0xfff & CmpData);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_GetCompareResult
 **			获取ADCB比较器结果
 ** \param [in] Compare : ADCB_CMP0 、ADCB_CMP1
 ** \return  1 /0
 ** \note
 *****************************************************************************/
uint32_t ADCB_GetCompareResult(uint32_t Compare)
{
    return ((ADCB->CMP[Compare] & ADCB_CMP_ADCCMPO_Msk) ? 1 : 0);
}

/*****************************************************************************
 ** \brief	ADCB_Start
 **			开启ADCB
 ** \param [in] none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_Start(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON |= ADCB_CON_ADCEN_Msk;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_Stop
 **			关闭ADCB
 ** \param [in] none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_Stop(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON &= ~(ADCB_CON_ADCEN_Msk);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableReset
 **			复位ADCB
 ** \param [in] none
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableReset(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->CON |= ADCB_CON_ADCRST_Msk;
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableCompareInt
 **			开启ADCB比较中断
 ** \param [in] none
 ** \return  none
 ** \note	只支持比较器 0
 *****************************************************************************/
void ADCB_EnableCompareInt(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->IMSC |= ADCB_IMSC_IMSC31_Msk;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableCompareInt
 **			关闭ADCB比较中断
 ** \param [in] none
 ** \return  none
 ** \note	只支持比较器 0
 *****************************************************************************/
void ADCB_DisableCompareInt(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->IMSC &= ~(ADCB_IMSC_IMSC31_Msk);
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_GetCompareIntFlag
 **			获取ADCB比较中断使能并且产生中断标志位
 ** \param [in] none
 ** \return  1:中断使能并且产生中断 0：无中断
 ** \note	只支持比较器 0
 *****************************************************************************/
uint32_t ADCB_GetCompareIntFlag(void)
{
    return ((ADCB->MIS & ADCB_MIS_MIS31_Msk) ? 1 : 0);
}
/*****************************************************************************
 ** \brief	ADCB_ClearCompareIntFlag
 **			清除ADCB比较中断标志位
 ** \param [in] none
 ** \return  none
 ** \note	只支持比较器 0
 *****************************************************************************/
void ADCB_ClearCompareIntFlag(void)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->ICLR |= (ADCB_ICLR_ICLR31_Msk);
    ADCB->LOCK = 0x00;
}

/*****************************************************************************
 ** \brief	ADCB_EnableChannelInt
 **			开启ADCB通道n中断
 ** \param [in]ChannelMask: ADCB_CH_0_MSK ~ ADCB_CH_30_MSK
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_EnableChannelInt(uint32_t ChannelMask)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->IMSC |= ChannelMask;
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_DisableChannelInt
 **			关闭ADCB通道n中断
 ** \param [in] ChannelMask: ADCB_CH_0_MSK ~ ADCB_CH_30_MSK
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_DisableChannelInt(uint32_t ChannelMask)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->IMSC &= ~(ChannelMask);
    ADCB->LOCK = 0x00;
}
/*****************************************************************************
 ** \brief	ADCB_GetChannelIntFlag
 **			获取ADCB通道n中断使能并且产生中断标志位
 ** \param [in] Channel:ADCB_CH_0 ~ ADCB_CH_30
 ** \return  1:中断使能并且产生中断 0：无中断
 ** \note
 *****************************************************************************/
uint32_t ADCB_GetChannelIntFlag(uint32_t Channel)
{
    return ((ADCB->MIS & (0x1UL << Channel)) ? 1 : 0);
}
/*****************************************************************************
 ** \brief	ADCB_ClearChannelIntFlag
 **			清除ADCB通道n中断标志位
 ** \param [in] Channel:ADCB_CH_0 ~ ADCB_CH_30
 ** \return  none
 ** \note
 *****************************************************************************/
void ADCB_ClearChannelIntFlag(uint32_t Channel)
{
    ADCB->LOCK = ADCB_LOCK_WRITE_KEY;
    ADCB->ICLR |= (0x01UL << Channel);
    ADCB->LOCK = 0x00;
}

// 用户部分
